package com.huangfu.learning.javabase.java.pattern.action.state;

/**
 * Created with IntelliJ IDEA.
 * Author: huangfu.daohui
 * Date: 2018/8/14
 * Time: 19:54
 * Version: 1.0
 * Description:状态模式：类的行为是基于它的状态改变的。跟策略模式类似
 * 参考：https://blog.csdn.net/seu_calvin/article/details/52779282
 * http://www.runoob.com/design-pattern/state-pattern.html
 * <p>
 * 优点：在不同状态需要有不同响应的使用场景下，避免了使用if/else导致代码臃肿，使代码结构清晰的同时保证了拓展性和维护性。
 * 缺点：状态模式的使用必然会增加类和对象的个数，如果使用不当将导致程序结构和代码的混乱。
 * <p>
 * 状态模式所涉及到的角色
 * 环境(Context)角色，也成上下文：定义客户端所感兴趣的接口，并且保留一个具体状态类的实例。这个具体状态类的实例给出此环境对象的现有状态。
 * 抽象状态(State)角色：定义一个接口，用以封装环境（Context）对象的一个特定的状态所对应的行为。
 * 具体状态(ConcreteState)角色：每一个具体状态类都实现了环境（Context）的一个状态所对应的行为。
 * <p>
 * 我们还是以一个例子入手：假设现在我们有一个饮水机，它有以下两个状态： 满桶，空桶。初始状态是满桶，容量是20。饮水机只有一个动作：press，每次press后都会使容量减1，一旦为0，则将状态设置为空桶，这时press没有水流出。
 **/
public class StatePattern {
    public static void main(String[] args) {
        //测试
        WaterDispenser dispenser = new WaterDispenser(new FullState());
        for (int i = 0; i < 100; ++i) {
            dispenser.press();
        }
    }
}

/**
 * 分配状态
 */
interface DispenserState {
    void press();
}

/**
 * 然后我们再定义有水桶和无水桶桶两个状态
 */
class FullState implements DispenserState {

    @Override
    public void press() {
        System.out.println("Water is pouring!");
    }
}

class NullState implements DispenserState {

    @Override
    public void press() {
        System.out.println("There is not water poured!");
    }
}

/**
 * 实现饮水机
 */
class WaterDispenser {
    private static int capacity = 20;
    private static DispenserState dispenserState;

    WaterDispenser(DispenserState state) {
        dispenserState = state;
    }

    private static void setState(DispenserState state) {
        dispenserState = state;
    }

    public DispenserState getState() {
        return dispenserState;
    }

    void press() {
        capacity--;
        if (capacity <= 0) {
            setState(new NullState());
        }
        dispenserState.press();
    }


//    下面是原始方法，看起来更简单，但是当场景很多的时候就要不停的写ifelse

//    private static int capacity = 20;
//
//    public void press() {
//        capacity--;
//        if (capacity <= 0) {
//            System.out.println("There is not water poured!");
//        } else {
//            System.out.println("Water is pouring!");
//        }
//    }
}